package com.xyh.builder;

import com.xyh.bean.Constants;
import com.xyh.bean.FieldInfo;
import com.xyh.bean.TableInfo;
import com.xyh.utils.DateUtils;
import com.xyh.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @Author: Hendrix Xie
 * @CreateTime: 2025-03-23 15:09:29
 * @Description: 生成业务实现类
 * @Version: 1.0
 */
public class BuildServiceImpl {
    private static final Logger logger = LoggerFactory.getLogger(BuildServiceImpl.class);

    public static void execute(TableInfo tableInfo) {
        // 初始化目录和文件
        File poDir = new File(Constants.PATH_SERVICE_IMPL);
        if (!poDir.exists() && !poDir.mkdirs()) {
            logger.error("创建ServiceImpl目录失败: {}", Constants.PATH_SERVICE_IMPL);
            return;
        }

        File poFile = new File(poDir, tableInfo.getBeanName()+Constants.SUFFIX_SERVICE + "Impl.java");

        // 生成Service类
        try (BufferedWriter bw = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(poFile), StandardCharsets.UTF_8))) {
            writePackage(bw); // 包声明
            writeImports(bw, tableInfo); // 导包区域
            writeClassComment(bw, tableInfo); // 类注释
            writeClassDefinition(bw, tableInfo); // 类定义
            writeFields(bw, tableInfo.getFieldList(), tableInfo); // 字段生成
            bw.write("}");
            bw.flush();
            logger.info("生成ServiceImpl成功: {}", poFile.getAbsolutePath());
        } catch (Exception e) {
            logger.error("生成ServiceImpl失败: 表名={}", tableInfo.getTableName(), e);
        }
    }
    private static String getMapperName(TableInfo tableInfo) {
        return StringUtils.lowerCaseFirstLetter(tableInfo.getBeanName())+ Constants.SUFFIX_MAPPER;
    }

    private static void writeFields(BufferedWriter bw, List<FieldInfo> fieldList, TableInfo tableInfo) throws IOException {
        //根据条件查询列表
        writeFieldComment(bw, "根据条件查询列表");
        bw.write("\t@Override\n");
        generateFindListByParam(bw, tableInfo);
        //根据条件查询数量
        writeFieldComment(bw, "根据条件查询数量");
        bw.write("\t@Override\n");
        generateFindListCountByParam(bw, tableInfo);
        //分页查询
        writeFieldComment(bw, "分页查询");
        bw.write("\t@Override\n");
        generateFindListByParamAndPage(bw, tableInfo);
        //新增
        writeFieldComment(bw, "新增");
        bw.write("\t@Override\n");
        generateAdd(bw, tableInfo);
        //批量新增
        writeFieldComment(bw, "批量新增");
        bw.write("\t@Override\n");
        generateBatchAdd(bw, tableInfo);
        //批量新增/修改
        writeFieldComment(bw, "批量新增/修改");
        bw.write("\t@Override\n");
        generateBatchAddOrUpdate(bw, tableInfo);
//        //根据主键查询
//        writeFieldComment(bw, "根据主键查询");
//        generateFindById(bw, tableInfo);
//        //根据主键修改
//        writeFieldComment(bw, "根据主键修改");
//        generateUpdateById(bw, tableInfo);
//        //根据主键删除
//        writeFieldComment(bw, "根据主键删除");
//        generateDeleteById(bw, tableInfo);

        //查主键逻辑
        Set<String> keyFieldNameSet = new HashSet<>();
        for (Map.Entry<String, List<FieldInfo>> entry : tableInfo.getKeyIndexMap().entrySet()) {
            List<FieldInfo> keyFieldList = entry.getValue();
            Integer index = 0;
            StringBuffer methodName = new StringBuffer();
            StringBuffer methodParams = new StringBuffer();
            StringBuffer methodParams2 = new StringBuffer();
            for (FieldInfo fieldInfo : keyFieldList) {
                index++;
                methodName.append(StringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName()));
                if(index<keyFieldList.size()){
                    methodName.append("And");
                }
                methodParams.append(fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName()  );
                methodParams2.append(fieldInfo.getPropertyName());
                if(index<keyFieldList.size()){
                    methodParams.append(",");
                    methodParams2.append(",");
                }
                keyFieldNameSet.add(fieldInfo.getPropertyName());
            }

            writeFieldComment(bw, "根据"+methodName + "查询");
            bw.write("\t@Override\n");
            bw.write("\tpublic "+tableInfo.getBeanName()+" findBy"+methodName+"("+ methodParams+"){\n");
            bw.write("\t\treturn "+getMapperName(tableInfo)+".selectBy"+methodName+"("+ methodParams2+");\n");
            bw.write("\t}\n");


            writeFieldComment(bw, "根据"+methodName + "修改");
            bw.write("\t@Override\n");
            bw.write("\tpublic Long updateBy"+methodName+"( "+tableInfo.getBeanName()+" entity, "+ methodParams+ "){\n");
            bw.write("\t\treturn "+getMapperName(tableInfo)+".updateBy"+methodName+"(entity,"+ methodParams2+");\n");
            bw.write("\t}\n");


            writeFieldComment(bw, "根据"+methodName + "删除");
            bw.write("\t@Override\n");
            bw.write("\tpublic Long deleteBy"+methodName+"("+methodParams +"){\n");
            bw.write("\t\treturn "+getMapperName(tableInfo)+".deleteBy"+methodName+"("+ methodParams2+");\n");
            bw.write("\t}\n");

        }
        //根据id删除
        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            if(!keyFieldNameSet.contains(fieldInfo.getPropertyName()) && fieldInfo.getPropertyName().toLowerCase().endsWith("id")){
                writeFieldComment(bw, "根据"+fieldInfo.getPropertyName() + "删除");
                bw.write("\t@Override\n");
                bw.write("\tpublic Long deleteBy"+StringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName())+"("+fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName()+"){\n");
                bw.write("\t\treturn "+getMapperName(tableInfo)+".deleteBy"+StringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName())+"("+ fieldInfo.getPropertyName()+");\n");
                bw.write("\t}\n");
            }
        }

    }


    private static void generateBatchAddOrUpdate(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\tpublic Long batchAddOrUpdate(List<"+tableInfo.getBeanName()+"> list){\n");
        bw.write("\t\treturn "+getMapperName(tableInfo)+".insertOrUpdateBatch(list);\n");
        bw.write("\t}\n");
    }

    private static void generateBatchAdd(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\tpublic Long batchAdd(List<"+tableInfo.getBeanName()+"> list){\n");
        bw.write("\t\treturn "+getMapperName(tableInfo)+".insertBatch(list);\n");
        bw.write("\t}\n");
    }

    private static void generateAdd(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\tpublic Long add("+tableInfo.getBeanName()+" bean){\n");
        bw.write("\t\treturn "+getMapperName(tableInfo)+".insertEntity(bean);\n");
        bw.write("\t}\n");
    }

    private static void generateFindListByParamAndPage(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\tpublic PaginationResultVO<" + tableInfo.getBeanName() + "> findListByPage(" + tableInfo.getBeanParamName() + " param){\n");
        bw.write("\t\t// 参数校验\n");
        bw.write("\t\tif (param == null || param.getCurrentPage() <= 0 || param.getPageSize() <= 0) {\n");
        bw.write("\t\t\tthrow new IllegalArgumentException(\"分页参数无效：currentPage 和 pageSize 必须大于 0\");\n");
        bw.write("\t\t}\n");
        bw.write("\t\tPaginationResultVO<" + tableInfo.getBeanName() + "> page = new PaginationResultVO<>();\n");
        bw.write("\t\ttry {\n");
        bw.write("\t\t\t// 查询总记录数\n");
        bw.write("\t\t\tLong total = " + getMapperName(tableInfo) + ".selectCountByCollection(param);\n");
        bw.write("\t\t\tif (total == null) {\n");
        bw.write("\t\t\t\ttotal = 0L;\n");
        bw.write("\t\t\t}\n");
        bw.write("\t\t\t// 创建分页对象\n");
        bw.write("\t\t\tif(param.getSimplePage() == null) {\n");
        bw.write("\t\t\t\tSimplePage<" + tableInfo.getBeanName() + "> sPage = new SimplePage<>(param.getCurrentPage(), param.getPageSize(), total);\n");
        bw.write("\t\t\t\tparam.setSimplePage(sPage);\n");
        bw.write("\t\t\t}\n");
        bw.write("\t\t\t// 设置分页结果\n");
        bw.write("\t\t\tpage.setTotal(total);\n");
        bw.write("\t\t\tpage.setCurrent(param.getCurrentPage());\n");
        bw.write("\t\t\tpage.setPageSize(param.getPageSize());\n");
        bw.write("\t\t\tpage.setTotalPages(param.getSimplePage().getTotalPages());\n");
        bw.write("\t\t\tpage.setList(" + getMapperName(tableInfo) + ".selectByParams(param));\n");
        bw.write("\t\t} catch (Exception e) {\n");
        bw.write("\t\t\tSystem.out.println(\"分页查询失败\");\n");
        bw.write("\t\t\treturn new PaginationResultVO<>();\n");
        bw.write("\t\t}\n");
        bw.write("\t\treturn page;\n");
        bw.write("\t}\n\n");
    }

    private static void generateFindListCountByParam(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\tpublic Long findCountByParam("+tableInfo.getBeanParamName()+" param){\n");
        bw.write("\t\treturn "+getMapperName(tableInfo)+".selectCountByCollection(param);\n");
        bw.write("\t}\n");

    }

    private static void generateFindListByParam(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\tpublic List<"+tableInfo.getBeanName()+"> findListByParam("+tableInfo.getBeanParamName()+" param){\n");
        bw.write("\t\treturn "+getMapperName(tableInfo)+".selectByParams(param);\n");
        bw.write("\t}\n");
    }

    private static void writeFieldComment(BufferedWriter bw, String comment) throws IOException {
        bw.write("\t/** ");
        bw.newLine();
        if (comment != null && !comment.isEmpty()) {
            bw.write("\t * " + comment);
            bw.newLine();
        } else {
            bw.write("\t * ");
            bw.newLine();
        }
        bw.write("\t */");
        bw.newLine();
    }

    private static void writeClassDefinition(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("@Service\n");
        bw.write("public class " + tableInfo.getBeanName() + Constants.SUFFIX_SERVICE + "Impl implements "+tableInfo.getBeanName() + Constants.SUFFIX_SERVICE+" {\n");
        bw.write("\t@Autowired\n");
        bw.write("\tprivate "+tableInfo.getBeanName()+ Constants.SUFFIX_MAPPER+"<"+getPoName(tableInfo)+", "+getQueryName(tableInfo)+"> "+StringUtils.lowerCaseFirstLetter(tableInfo.getBeanName())+ Constants.SUFFIX_MAPPER+";\n");
    }

    private static String getQueryName(TableInfo tableInfo) {
        return tableInfo.getBeanParamName();
    }

    private static String getPoName(TableInfo tableInfo) {
        return tableInfo.getBeanName();
    }

    private static void writeClassComment(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("/**");
        bw.newLine();
        bw.write(" * " + (null != tableInfo.getComment() ? tableInfo.getComment() : tableInfo.getBeanName()) + " 业务接口");
        bw.newLine();
        bw.write(" * ");
        bw.newLine();
        bw.write(" * 对应数据库表: " + tableInfo.getTableName());
        bw.newLine();
        bw.write(" * @author " + Constants.AUTHOR);
        bw.newLine();
        bw.write(" * @date " + DateUtils.format(new Date(), DateUtils.YYYY_MM_DD_HH_MM_SS));
        bw.newLine();
        bw.write(" */");
        bw.newLine();

    }

    private static void writeImports(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        // 基本导入
        writeBasicImports(bw,tableInfo);

    }

    // 基本导入
    private static void writeBasicImports(BufferedWriter bw,TableInfo tableInfo) throws IOException {
        String[] imports = {
                "java.util.List",
                "org.springframework.stereotype.Service",
                "org.springframework.beans.factory.annotation.Autowired",
                Constants.PACKAGE_PO + "." + tableInfo.getBeanName(),
                Constants.PACKAGE_PARAM + "." + tableInfo.getBeanParamName(),
                Constants.PACKAGE_VO + "." + "PaginationResultVO",
                Constants.PACKAGE_SERVICE +"." + tableInfo.getBeanName() + Constants.SUFFIX_SERVICE,
                Constants.PACKAGE_MAPPER +"." + tableInfo.getBeanName() + Constants.SUFFIX_MAPPER,
                Constants.PACKAGE_PARAM + "." + "SimplePage"
        };

        for (String imp : imports) {
            bw.write("import " + imp + ";");
            bw.newLine();
        }
    }

    private static void writePackage(BufferedWriter bw) throws IOException {
        bw.write("package " + Constants.PACKAGE_SERVICE_IMPL + ";");
        bw.newLine();
        bw.newLine();
    }

}